package com.putiman.client;

import com.putiman.protocol.RequestProtocol;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * rpc客户端
 */
public class RPCClient {
    /**
     * 通过动态代理获取调用接口对应实例
     *
     * @param interfaceClass
     * @param address
     * @param <T>
     * @return
     */
    public static <T> T getRemoteProxy(Class<T> interfaceClass, InetSocketAddress address) {
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
                new Class[]{interfaceClass}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        try (Socket socket = new Socket()) {
                            //通过网络连接服务端
                            socket.connect(address);
                            try (
                                    //获取输出流
                                    ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
                                    //获取输入流
                                    ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
                            ) {
                                //创建一个请求的协议对象
                                RequestProtocol requestProtocol = new RequestProtocol();
                                requestProtocol.setInterfaceClassName(interfaceClass.getName());
                                requestProtocol.setMethodName(method.getName());
                                requestProtocol.setParameterTypes(method.getParameterTypes());
                                requestProtocol.setParameterValues(args);
                                //序列化协议对象(放入到网络中)
                                outputStream.writeObject(requestProtocol);
                                //反序列化（把服务端放入的数据获取出来）
                                Object result = inputStream.readObject();
                                return result;

                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }


                        return null;
                    }
                });
    }
}
